package com.demo.chapter11future.asyncadddiscount;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Stream;

import com.demo.chapter11future.sync.Shop;

/**CompletableFuture类实现了CompletionStage和Future接口。Future是Java 5添加的类，用来描述一个异步计算的结果，但是获取一个结果时方法较少,
 * 要么通过轮询isDone，确认完成后，调用get()获取值，要么调用get()设置一个超时时间。但是这个get()方法会阻塞住调用线程，这种阻塞的方式显然和我们
 * 的异步编程的初衷相违背。为了解决这个问题，JDK吸收了guava的设计思想，加入了Future的诸多扩展功能形成了CompletableFuture。
 *
 * CompletionStage是一个接口，从命名上看得知是一个完成的阶段，它里面的方法也标明是在某个运行阶段得到了结果之后要做的事情。
 * @author DELL
 *
 */
public class Demo3 {

	public static void thenApply() {
		/**
		 * 首先说明一下已Async结尾的方法都是可以异步执行的，如果指定了线程池，会在指定的线程池中执行，如果没有指定，默认会在ForkJoinPool.commonPool()中执行，
		 * 下文中将会有好多类似的，都不详细解释了。关键的入参只有一个Function，它是函数式接口，所以使用Lambda表示起来会更加优雅。
		 * 它的入参是上一个阶段计算后的结果，返回值是经过转化后结果。
		 * */
		String result = CompletableFuture.supplyAsync(() -> "hello").thenApply(s -> s + " world").join();
		System.out.println(result);
	}

	//进行消耗
	public static void thenAccept(){
	    CompletableFuture.supplyAsync(() -> "hello").thenAccept(s -> System.out.println(s+" world"));
	}

	//对上一步的计算结果不关心，执行下一个操作。
	//thenRun它的入参是一个Runnable的实例，表示当得到上一步的结果时的操作。
	public static void thenRun() {
		CompletableFuture.supplyAsync(() -> {
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "hello";
		}).thenRun(() -> System.out.println("hello world"));
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	//结合两个CompletionStage的结果，进行转化后返回
	//它需要原来的处理返回值，并且other代表的CompletionStage也要返回值之后，利用这两个返回值，进行转换后返回指定类型的值。
	public static void thenCombine() {
		String result = CompletableFuture.supplyAsync(() -> {
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "hello";
		}).thenCombine(CompletableFuture.supplyAsync(() -> {
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "world";
		}), (s1, s2) -> s1 + " " + s2).join();
		System.out.println(result);
	}

	//结合两个CompletionStage的结果，进行消耗
	//它需要原来的处理返回值，并且other代表的CompletionStage也要返回值之后，利用这两个返回值，进行消耗。
	public static void thenAcceptBoth() {
		CompletableFuture.supplyAsync(() -> {
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "hello";
		}).thenAcceptBoth(CompletableFuture.supplyAsync(() -> {
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "world";
		}), (s1, s2) -> System.out.println(s1 + " " + s2));
		try {
			Thread.sleep(6000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	//在两个CompletionStage都运行完执行。
	//不关心这两个CompletionStage的结果，只关心这两个CompletionStage执行完毕，之后在进行操作（Runnable）。
	public static void runAfterBoth() {
		CompletableFuture.supplyAsync(() -> {
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "s1";
		}).runAfterBothAsync(CompletableFuture.supplyAsync(() -> {
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "s2";
		}), () -> System.out.println("hello world"));
		while (true) {
		}
	}

	public static void main(String[] args) {
		thenApply();
		thenAccept();
		thenRun();
		thenCombine();
		thenAcceptBoth();
		runAfterBoth();
	}

}
